#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>

#include <stat_tools.h>
#include <log.h>
#include <Singleton.h>
#include <cgi_control.h>
#include <stat_manager.h>

USING_HTTP_SVR_NS;

TCGIControl* g_pCgiControl = NULL;

#define BUF_SIZE 2048

u_long web_max_req = 0;
u_long web_min_req = 0;
u_long web_mod_req = 0;
u_long web_total_req = 0;
u_long web_req_num = 0;

u_long web_max_req_rate = 0;
u_long web_min_req_rate = 0;
u_long web_mod_req_rate = 0;
u_long web_total_req_rate = 0;
u_long web_req_rate_num = 0;

u_long web_max_rsp = 0;
u_long web_min_rsp = 0;
u_long web_mod_rsp = 0;
u_long web_total_rsp = 0;
u_long web_rsp_num = 0;

u_long web_max_rsp_rate = 0;
u_long web_min_rsp_rate = 0;
u_long web_mod_rsp_rate = 0;
u_long web_total_rsp_rate = 0;
u_long web_rsp_rate_num = 0;

u_long helper_max_req = 0;
u_long helper_min_req = 0;
u_long helper_mod_req = 0;
u_long helper_total_req = 0;
u_long helper_req_num = 0;

u_long helper_max_req_rate = 0;
u_long helper_min_req_rate = 0;
u_long helper_mod_req_rate = 0;
u_long helper_total_req_rate = 0;
u_long helper_req_rate_num = 0;

u_long helper_max_rsp = 0;
u_long helper_min_rsp = 0;
u_long helper_mod_rsp = 0;
u_long helper_total_rsp = 0;
u_long helper_rsp_num = 0;

u_long helper_max_rsp_rate = 0;
u_long helper_min_rsp_rate = 0;
u_long helper_mod_rsp_rate = 0;
u_long helper_total_rsp_rate = 0;
u_long helper_rsp_rate_num = 0;

u_long cgi_max_req[MAX_CGI_COUNT];
u_long cgi_min_req[MAX_CGI_COUNT];
u_long cgi_mod_req[MAX_CGI_COUNT];
u_long cgi_total_req[MAX_CGI_COUNT];
u_long cgi_req_num[MAX_CGI_COUNT];

u_long cgi_max_req_rate[MAX_CGI_COUNT];
u_long cgi_min_req_rate[MAX_CGI_COUNT];
u_long cgi_mod_req_rate[MAX_CGI_COUNT];
u_long cgi_total_req_rate[MAX_CGI_COUNT];
u_long cgi_req_rate_num[MAX_CGI_COUNT];

u_long cgi_max_rsp[MAX_CGI_COUNT];
u_long cgi_min_rsp[MAX_CGI_COUNT];
u_long cgi_mod_rsp[MAX_CGI_COUNT];
u_long cgi_total_rsp[MAX_CGI_COUNT];
u_long cgi_rsp_num[MAX_CGI_COUNT];

u_long cgi_max_rsp_rate[MAX_CGI_COUNT];
u_long cgi_min_rsp_rate[MAX_CGI_COUNT];
u_long cgi_mod_rsp_rate[MAX_CGI_COUNT];
u_long cgi_total_rsp_rate[MAX_CGI_COUNT];
u_long cgi_rsp_rate_num[MAX_CGI_COUNT];

int get_statistic_info(char* buffer, char* key, u_long& max, u_long& min, u_long& mod, u_long& total, u_long& num);

void* map_file (const char* filename, int size)
{
    int fd = ::open(filename, O_RDWR|O_CREAT, 0666);
    void *map = NULL;

    if(fd >= 0)
    {
        if(size > 0){
            int dummy = ftruncate(fd, size);
			if(dummy !=0){};
		}
        else
            size = lseek(fd, 0L, SEEK_END);

        if(size > 0)
            map = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
        ::close(fd);
    } else if(size > 0) {
        map = mmap(0, size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS, -1, 0);
    }

    if(map == MAP_FAILED)
    {
        map = NULL;
    }

    return map;
}

int main (int argc, char* argv[])
{
    int c;
    char res_file[256]     = {'\0'};
    char cgi_conf_file[256] = {'\0'};
    
    if (argc < 3)
    {
        fprintf (stderr, "usage: %s -f <cgiconfig.xml> -r <result file>\n", argv[0]);

        return 0;
    }

    while ((c = getopt (argc, argv, "f:r:h")) != -1) {
		switch (c) {
        case 'f':
            strncpy (cgi_conf_file, optarg, sizeof (cgi_conf_file) - 1);
            if (access(cgi_conf_file, F_OK) != 0)
            {
                fprintf (stderr, "cgi config file [%s] read failed, msg[%s]\n", cgi_conf_file, strerror(errno));
                return -1;
            }
            break;
        case 'r':
            strncpy (res_file, optarg, sizeof (res_file) - 1);
            if (access(res_file, F_OK) != 0)
            {
                fprintf (stderr, "result file [%s] read failed, msg[%s]\n", res_file, strerror(errno));
                return -1;
            }
            break;
		case 'h':
            fprintf (stderr, "usage: %s -f <config file> -r <result file>\n", argv[0]);
			return 0;
		default:
            fprintf (stderr, "usage: %s -f <config file> -r <result file>\n", argv[0]);
			return 0;
        }
    }

    if(TGlobal::DaemonInit(cgi_conf_file) < 0)
		return -1;

    g_pCgiControl = TCGIControl::Instance ();
    if (NULL == g_pCgiControl)
    {
        fprintf (stderr, "get TCGIControl instance failed, msg[%s]\n", strerror(errno));
        return -1;
    }

    if (g_pCgiControl->open(cgi_conf_file) == -1)
    {
        fprintf (stderr, "TCGIControl init failed, msg[%s]\n", strerror(errno));
        return -1;
    }
 
    TCGIInfo* cgi_list = g_pCgiControl->get_cgi_info ();
    int cgi_count = g_pCgiControl->get_cgi_count ();
    
    char buffer[BUF_SIZE] = {'\0'};
    char key[BUF_SIZE] = {'\0'};
    FILE* fp = NULL;
    int try_times = 0;

    while(try_times < 3)
    {
        if((fp = fopen(res_file, "r+")) == NULL)
        {
            try_times ++;
            sleep(1);
            continue;
        }

        break;
    }

    if(NULL == fp)
    {
        fprintf(stderr, "open result file [%s] failed, error[%s]\n", res_file, strerror(errno));
        return -1;
    }

    fseek(fp, 0, SEEK_SET);

    while(!feof(fp))
    {
        buffer[0] ='\0'; 
        if(NULL == fgets(buffer, BUF_SIZE - 1, fp))
        {
            break;
        }

        if(0 == get_statistic_info(buffer, (char*)"Web_Total_Req=", web_max_req, 
                    web_min_req, web_mod_req, web_total_req, web_req_num))
            continue;

        if(0 == get_statistic_info(buffer, (char*)"Web_Req_Rate=", web_max_req_rate, 
                    web_min_req_rate, web_mod_req_rate, web_total_req_rate, web_req_rate_num))
            continue;

        if(0 == get_statistic_info(buffer, (char*)"Web_Total_Rsp=", web_max_rsp, 
                    web_min_rsp, web_mod_rsp, web_total_rsp, web_rsp_num))
            continue;

        if(0 == get_statistic_info(buffer, (char*)"Web_Rsp_Rate=", web_max_rsp_rate, 
                    web_min_rsp_rate, web_mod_rsp_rate, web_total_rsp_rate, web_rsp_rate_num))
            continue;

        if(0 == get_statistic_info(buffer, (char*)"Helper_Total_Req=", helper_max_req, 
                    helper_min_req, helper_mod_req, helper_total_req, helper_req_num))
            continue;

        if(0 == get_statistic_info(buffer, (char*)"Helper_Req_Rate=", helper_max_req_rate, 
                    helper_min_req_rate, helper_mod_req_rate, helper_total_req_rate, helper_req_rate_num))
            continue;

        if(0 == get_statistic_info(buffer, (char*)"Helper_Total_Rsp=", helper_max_rsp, 
                    helper_min_rsp, helper_mod_rsp, helper_total_rsp, helper_rsp_num))
            continue;

        if(0 == get_statistic_info(buffer, (char*)"Helper_Rsp_Rate=", helper_max_rsp_rate, 
                    helper_min_rsp_rate, helper_mod_rsp_rate, helper_total_rsp_rate, helper_rsp_rate_num))
            continue;

        for(int i=0; i<cgi_count; i++)
        {
            snprintf(key, BUF_SIZE-1, "%s_Total_Req=", cgi_list[i]._szCgiName); 
            if(0 == get_statistic_info(buffer, key, cgi_max_req[i], 
                    cgi_min_req[i], cgi_mod_req[i], cgi_total_req[i], cgi_req_num[i]))
                break;
    
            snprintf(key, BUF_SIZE-1,"%s_Req_Rate=", cgi_list[i]._szCgiName); 
            if(0 == get_statistic_info(buffer, key, cgi_max_req_rate[i], 
                    cgi_min_req_rate[i], cgi_mod_req_rate[i], cgi_total_req_rate[i], cgi_req_rate_num[i]))
                break;

            snprintf(key, BUF_SIZE-1,"%s_Total_Rsp=", cgi_list[i]._szCgiName); 
            if(0 == get_statistic_info(buffer, key, cgi_max_rsp[i], 
                    cgi_min_rsp[i], cgi_mod_rsp[i], cgi_total_rsp[i], cgi_rsp_num[i]))
                break;

            snprintf(key, BUF_SIZE-1,"%s_Rsp_Rate=", cgi_list[i]._szCgiName); 
            if(0 == get_statistic_info(buffer, key, cgi_max_rsp_rate[i], 
                    cgi_min_rsp_rate[i], cgi_mod_rsp_rate[i], cgi_total_rsp_rate[i], cgi_rsp_rate_num[i]))
                break;
        }
    }
   
    //truncate the file content
    int fd = -1;
    fd = fileno(fp);
    if(fd != -1){
        int dummy = ftruncate(fd, 0);
		if(dummy !=0){}
	}

    fclose(fp);
    
    printf("INFO:%-17s %-17s %-17s %-17s %-17s %-17s %-17s %-17s\n", "WebTotalReq", "WebReqRate(r/s)", "WebTotalRsp",    
            "WebRspRate(r/s)","HelperTotalReq", "HlperReqRate(r/s)", "HelperTotalRsp", "HlperRspRate(r/s)");

    printf("INFO:%-5lu-%-5lu-%-5lu ", web_max_req, web_mod_req, web_min_req);
    printf("%-5lu-%-5lu-%-5lu ", web_max_req_rate, web_mod_req_rate, web_min_req_rate);
    printf("%-5lu-%-5lu-%-5lu ", web_max_rsp, web_mod_rsp, web_min_rsp);
    printf("%-5lu-%-5lu-%-5lu ", web_max_rsp_rate, web_mod_rsp_rate, web_min_rsp_rate);
    printf("%-5lu-%-5lu-%-5lu ", helper_max_req, helper_mod_req, helper_min_req);
    printf("%-5lu-%-5lu-%-5lu ", helper_max_req_rate, helper_mod_req_rate, helper_min_req_rate);
    printf("%-5lu-%-5lu-%-5lu ", helper_max_rsp, helper_mod_rsp, helper_min_rsp);
    printf("%-5lu-%-5lu-%-5lu\n", helper_max_rsp_rate, helper_mod_rsp_rate, helper_min_rsp_rate);
    
    for(int i=0; i<cgi_count; i++)
    {
        printf("INFO:%-51s %-17s %-17s %-17s %-17s\n", cgi_list[i]._szCgiName, "TotalReq", "ReqRate(r/s)", 
                "TotalRsp", "RspRate(r/s)");
        printf("INFO:%-51s ","statistic data:");
        printf("%-5lu-%-5lu-%-5lu ", cgi_max_req[i], cgi_mod_req[i], cgi_min_req[i]);
        printf("%-5lu-%-5lu-%-5lu ", cgi_max_req_rate[i], cgi_mod_req_rate[i], cgi_min_req_rate[i]);
        printf("%-5lu-%-5lu-%-5lu ", cgi_max_rsp[i], cgi_mod_rsp[i], cgi_min_rsp[i]);
        printf("%-5lu-%-5lu-%-5lu\n", cgi_max_rsp_rate[i], cgi_mod_rsp_rate[i], cgi_min_rsp_rate[i]);
    }
    
    return 0;
}

int get_statistic_info(char* buffer, char* key, u_long& max, u_long& min, u_long& mod, u_long& total, u_long& num)
{
    if(NULL == buffer)
        return -1;

    char* p = NULL, *p1 = NULL;
    p = strstr(buffer, key);
    if(NULL == p)
        return -1;

    p1 = buffer + strlen(key);
    if(NULL == p1)
        return -1;

    int i = 0;
    while(p1[i] != '\0')
    {
        if(p1[i] == ' ' || p1[i] == 'r')
        {    
            p1[i] = '\0';
            break;
        }

        i++;
    }
    
    u_long value = 0;
    if((value = atoi(p1)) <= 0)
        return -1;

    if(value > max)
        max = value;

    if( value < min)
        min = value;
    
    if(0 == min)
        min = value;

    total += value;
    num ++;
    
    mod = total/num;

    return 0;
}
